package com.meida.module.arc.provider.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.meida.common.base.entity.EntityMap;
import com.meida.common.base.utils.FlymeUtils;
import com.meida.common.mybatis.base.service.impl.BaseServiceImpl;
import com.meida.common.mybatis.model.ResultBody;
import com.meida.common.mybatis.query.CriteriaDelete;
import com.meida.common.mybatis.query.CriteriaQuery;
import com.meida.common.mybatis.query.CriteriaSave;
import com.meida.common.mybatis.query.CriteriaUpdate;
import com.meida.common.security.OpenHelper;
import com.meida.common.security.OpenUser;
import com.meida.common.utils.ApiAssert;
import com.meida.module.arc.client.constants.ArchiveConstants;
import com.meida.module.arc.client.entity.ArcDict;
import com.meida.module.arc.client.enums.ArchiveEnumInteger;
import com.meida.module.arc.client.utils.ArcUtils;
import com.meida.module.arc.provider.mapper.ArcDictMapper;
import com.meida.module.arc.provider.service.ArcDictService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 档案字典接口实现类
 *
 * @author flyme
 * @date 2021-11-17
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class ArcDictServiceImpl extends BaseServiceImpl<ArcDictMapper, ArcDict> implements ArcDictService {

    /**
     * 半段字典编码是否重复
     * @param qzId
     * @param dictCode
     * @return
     */
    private Boolean checkDictCode(Long qzId,String dictCode,Boolean isSystem){
        CriteriaQuery<ArcDict> query = new CriteriaQuery<ArcDict>(ArcDict.class);
        query.lambda().eq(ArcDict::getDictCode, dictCode).eq(ArcDict::getQzId, qzId);
        /*if(isSystem==null||!isSystem){
            query.lambda().and(qw->qw.eq(ArcDict::getQzId,qzId).or().eq(ArcDict::getIsSystem, ArchiveEnumInteger.IS_SYSTEM.getCode()));
        }*/
        Long count = this.baseMapper.selectCount(query);
        Boolean flag = count == null || count == 0 ? true : false;
        if (!flag) {
            List<ArcDict> arcDicts = this.baseMapper.selectList(query);
            ApiAssert.failure("当前字典代码" + dictCode + "与" + arcDicts.get(0).getDictName() + "的字典代码重复");
        }
        return flag;
    }

    private String genSysCode(Long parentId){
        String parentSysCode = null;
        //1查询父节点sysCode
        if(!ArchiveConstants.ROOT_PARENT_ID.equals(parentId)&&FlymeUtils.isNotEmpty(parentId)){
            ArcDict dict = getById(parentId);
            ApiAssert.isNotEmpty("父级字典不能为空",dict);
            parentSysCode = dict.getSysCode();
        }
        //2查询子节点最大sysCode
        CriteriaQuery<ArcDict> query = new CriteriaQuery<ArcDict>(ArcDict.class);
        query.lambda().eq(ArcDict::getParentId,parentId);
        query.orderByDesc("sysCode");
        query.limit(1);
        ArcDict preSysCodeObj = getOne(query);
        if(preSysCodeObj==null){
            return ArcUtils.genNextSysCode(parentSysCode,null);
        }else{
            return ArcUtils.genNextSysCode(parentSysCode,preSysCodeObj.getSysCode());
        }
    }

    @Override
    public ResultBody beforeAdd(CriteriaSave cs, ArcDict dict, EntityMap extra) {
        ApiAssert.isNotEmpty("全宗id不能为空",dict.getQzId());
        ApiAssert.isNotEmpty("父id不能为空",dict.getParentId());
        //TODO 判断是当前用户是否为管理员
        OpenUser user = OpenHelper.getUser();
        if (ArchiveEnumInteger.IS_ADMIN.getCode().equals(user.getSuperAdmin())) {
            //dict.setIsSystem(ArchiveEnumInteger.IS_ADMIN.getCode());
        }
        dict.setIsSystem(ArchiveEnumInteger.IS_NOT_SYSTEM.getCode());
        //校验同全宗下编码是否重复
        if (!checkDictCode(dict.getQzId(), dict.getDictCode(), dict.getIsSystem() != null && dict.getIsSystem() == 1 ? true : false)) {
            return ResultBody.failed("一个全宗内字典编码不能重复");
        }

        if (!ArcUtils.checkCode(dict.getDictCode())) {
            ApiAssert.failure("字典编码长度1-9位且包含数字 字母 下划线");
        }

        //生成序号
        CriteriaQuery<ArcDict> query = new CriteriaQuery<ArcDict>(ArcDict.class);
        query.eq("parentId", dict.getParentId());
        query.orderByDesc("seq");
        query.limit(1);
        ArcDict dictObj = this.baseMapper.selectOne(query);
        if (FlymeUtils.isEmpty(dictObj)) {
            dict.setSeq(0);
        }else{
            dict.setSeq(dictObj.getSeq()==null?0:dictObj.getSeq()+1);
        }

        //生成sysCOde
        dict.setSysCode(genSysCode(dict.getParentId()));

        return ResultBody.ok();
    }

    @Override
    public ResultBody afterAdd(CriteriaSave cs, ArcDict arcDict, EntityMap extra) {
        loadData2Redis();
        return ResultBody.ok("保存成功", arcDict);
    }

    @Override
    public ResultBody beforeEdit(CriteriaUpdate<ArcDict> cu, ArcDict t, EntityMap extra) {
        //TODO 判断是当前用户是否为管理员
        ArcDict dict = this.getById(t.getDictId());
        if(FlymeUtils.isEmpty(dict)){
            return ResultBody.failed("不存在要编辑的对象");
        }
        if(ArchiveEnumInteger.IS_SYSTEM.getCode().equals(dict.getIsSystem())){
            //TODO 判断是当前用户是否为管理员
            OpenUser user = OpenHelper.getUser();
            if(!ArchiveEnumInteger.IS_ADMIN.getCode().equals(user.getSuperAdmin())){
                return ResultBody.failed("非管理员无法编辑系统字典");
            }
        }
        if(FlymeUtils.isEmpty(dict.getDictCode())&&FlymeUtils.isEmpty(t.getDictCode())){
            return ResultBody.failed("门类编码不能为空");
        }

        //校验同全宗下编码是否重复
        if(FlymeUtils.isNotEmpty(t.getDictCode())
                && !t.getDictCode().toLowerCase().equals(dict.getDictCode().toLowerCase())
                &&!checkDictCode(dict.getQzId(),t.getDictCode(),dict.getIsSystem()!=null&&dict.getIsSystem()==1?true:false)){
            return ResultBody.failed("一个全宗内字典编码不能重复");
        }
        return ResultBody.ok();


    }

    @Override
    public ResultBody afterEdit(CriteriaUpdate cu, ArcDict arcDict, EntityMap extra) {
        loadData2Redis();
        return ResultBody.ok("更新成功", arcDict);
    }

    @Override
    public ResultBody beforeDelete(CriteriaDelete<ArcDict> cd) {
        ArcDict dict = this.getById(cd.getIdValue());
        if(FlymeUtils.isEmpty(dict)){
            return ResultBody.failed("不存在要删除的对象");
        }
        if(ArchiveEnumInteger.IS_SYSTEM.getCode().equals(dict.getIsSystem())){
            //TODO 判断是当前用户是否为管理员
            OpenUser user = OpenHelper.getUser();
            if(!ArchiveEnumInteger.IS_ADMIN.getCode().equals(user.getSuperAdmin())){
                return ResultBody.failed("非管理员无法删除系统字典");
            }
        }
        return ResultBody.ok();
    }


    @Override
    public ResultBody afterDelete(CriteriaDelete cd, Long[] ids) {
        loadData2Redis();
        return super.afterDelete(cd, ids);
    }

    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public ResultBody beforePageList(CriteriaQuery<ArcDict> cq, ArcDict dict, EntityMap requestMap) {
      cq.orderByDesc("dict.createTime");
      return ResultBody.ok();
    }

    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public ResultBody beforeListEntityMap(CriteriaQuery<ArcDict> cq, ArcDict t, EntityMap requestMap) {
        ApiAssert.isNotEmpty("全宗id不能为空",t.getQzId());
        //查询所有全宗id一致的和系统默认的
        cq.and(ew->{
            ew.eq("qzId",t.getQzId())
                    .or().eq("isSystem",ArchiveEnumInteger.IS_SYSTEM.getCode());
        });
        //根据父parentDictCode查询所有子级
        String parentDictCode = requestMap.get("parentDictCode");
        if(FlymeUtils.isNotEmpty(parentDictCode)){
            cq.and(qw->{
                qw.inSql("parentId","select dictId from arc_dict where dictCode='"+parentDictCode+"'");
            });
        }

        //根据code查询所有的数据
        cq.eq("dictCode");

        //根据parentId查询所有子级
        if(FlymeUtils.isNotEmpty(t.getParentId())){
            cq.and(qw->{
                qw.eq("parentId",t.getParentId());
            });
        }

        return ResultBody.ok();
    }

    @Override
    public ResultBody upOrDown(Map var1) {
        ApiAssert.isNotEmpty("门类id不能为空",var1.get("dictId"));
        ApiAssert.isNotEmpty("移动类型不能为空",var1.get("type"));
        //排序为从小到大排   type为1为上移  2为下移
        Long dictId = NumberUtil.parseLong(var1.get("dictId")+"");
        Integer type = NumberUtil.parseInt(var1.get("type")+"");
        if(type!=1&&type!=2){
            ApiAssert.failure("移动类型只能为上移或下移");
        }
        ArcDict dict = this.getById(dictId);
        CriteriaQuery<ArcDict> query = new CriteriaQuery<ArcDict>(ArcDict.class);
        query.lambda().eq(ArcDict::getParentId,dict.getParentId());//查询同级别的
        query.orderByAsc("seq");//基于seq从大到小排序
        List<ArcDict> list = this.list(query);
        int sourceIndex = -1;
        int targetIndex = -1;
        for(int i=0;i<list.size();i++){
            ArcDict obj = list.get(i);
            if(obj.getDictId().equals(dictId)){
                if(type==1){//上移
                    if(i==0){
                        return ResultBody.failed("无法上移");
                    }else{
                        sourceIndex = i;
                        targetIndex = i-1;
                    }
                }else if(type==2){//下移
                    if(i==list.size()-1){
                        return ResultBody.failed("无法下移");
                    }else{
                        sourceIndex = i;
                        targetIndex = i+1;
                    }
                }
            }
        }
        if(sourceIndex<0||targetIndex<0){
            return ResultBody.failed("移动错误");
        }
        Long targetId = list.get(sourceIndex).getDictId();
        list.get(sourceIndex).setDictId(list.get(targetIndex).getDictId());
        list.get(targetIndex).setDictId(targetId);
        List<ArcDict> updateObj = new ArrayList<>();
        for(int i=0;i<list.size();i++){
            ArcDict obj = new ArcDict();
            obj.setDictId(list.get(i).getDictId());
            obj.setSeq(i);
            updateObj.add(obj);
        }
        this.saveOrUpdateBatch(updateObj);
        return ResultBody.ok();
    }

    @Override
    public ResultBody getTreeByParentIdOrParentDictCode(Map var1) {
        Object parentId = var1.get("parentId");
        Object parentDictCode = var1.get("parentDictCode");
        Object qzId = var1.get("qzId");
        if(FlymeUtils.isEmpty(parentId)&&FlymeUtils.isEmpty(parentDictCode)){
            ApiAssert.failure("父id和父编码不能同时为空");
        }
        if(FlymeUtils.isNotEmpty(parentId)&&FlymeUtils.isNotEmpty(parentDictCode)){
            ApiAssert.failure("父id和父编码不能同时非空");
        }
        ApiAssert.isNotEmpty("全宗id不能为空",qzId);

        CriteriaQuery<ArcDict> query = new CriteriaQuery<ArcDict>(ArcDict.class);
        if(FlymeUtils.isNotEmpty(parentId)){
            if(ArchiveConstants.ROOT_PARENT_ID.equals(Long.parseLong(parentId.toString()))){
                return this.listEntityMap(var1);
            }
            query.lambda().eq(ArcDict::getDictId,Long.parseLong(parentId+""));
        }else{
            query.lambda().eq(ArcDict::getDictCode,parentDictCode.toString());
        }
        //根据全宗id过滤   或   类型属于系统级别
        query.and(wrap->{
           wrap.lambda().eq(ArcDict::getQzId,Long.parseLong(qzId.toString()))
                   .or().eq(ArcDict::getIsSystem,ArchiveEnumInteger.IS_TRUE.getCode());
        });
        ArcDict obj = getOne(query);
        if(FlymeUtils.isEmpty(obj)){
            ApiAssert.failure("根据父id或者父编码无法查询到内容");
        }
        CriteriaQuery<ArcDict> listQuery = new CriteriaQuery<ArcDict>(ArcDict.class);
        listQuery.likeRight("sysCode",obj.getSysCode());
        List<ArcDict> list = list(listQuery);
        return ResultBody.ok(list);
    }

    @Override
    public ResultBody list4Redis(Map params) {

        ArcDict t = BeanUtil.toBean(params, ArcDict.class);

        ApiAssert.isNotEmpty("全宗id不能为空", t.getQzId());
        List<ArcDict> list = redisUtils.getList(ArchiveConstants.ARC_DICT_PREFIX);
        if (CollUtil.isEmpty(list)) {
            loadData2Redis();
            list = redisUtils.getList(ArchiveConstants.ARC_DICT_PREFIX);
        }

        Stream<ArcDict> arcDictStream = list.stream().filter(arcDict -> arcDict.getQzId().equals(t.getQzId()) || ArchiveEnumInteger.IS_SYSTEM.getCode().equals(arcDict.getIsSystem()));

        List<ArcDict> result = new ArrayList<>();
        //根据父parentDictCode查询所有子级
        String parentDictCode = MapUtil.getStr(params, "parentDictCode");
        if (FlymeUtils.isNotEmpty(parentDictCode)) {


            List<ArcDict> collect = arcDictStream.filter(a -> a.getDictCode().equals(parentDictCode)).collect(Collectors.toList());
            for (ArcDict arcDict : collect) {
                result.addAll(arcDictStream.filter(a -> a.getParentId().equals(arcDict.getDictId())).collect(Collectors.toList()));

            }
        } else {
            result = arcDictStream.collect(Collectors.toList());
            ;
        }

        if (StrUtil.isNotEmpty(t.getDictCode())) {
            result = result.stream().filter(a -> a.getDictCode().equals(t.getDictCode())).collect(Collectors.toList());
        }


        //根据parentId查询所有子级
        if (FlymeUtils.isNotEmpty(t.getParentId())) {

            result = result.stream().filter(a -> a.getParentId().equals(t.getParentId())).collect(Collectors.toList());

        }

        return ResultBody.ok(result);
    }


    synchronized void loadData2Redis() {
        if (redisUtils.hasKey(ArchiveConstants.ARC_DICT_PREFIX)) {
            redisUtils.del(ArchiveConstants.ARC_DICT_PREFIX);
        }
        //List<ArcDict> list = this.list();
        //redisUtils.setList(ArchiveConstants.ARC_DICT_PREFIX,list);
    }
}
